public class TElementoAB implements IElementoAB {
	@SuppressWarnings("rawtypes")
	public Comparable etiqueta;
	public IElementoAB hijoIzq;
	public IElementoAB hijoDer;
	public Object datos;

	/**
	 * @param unaEtiqueta
	 * @param unosDatos
	 */
	@SuppressWarnings("rawtypes")
	public TElementoAB(Comparable unaEtiqueta, Object unosDatos) {
		etiqueta = unaEtiqueta;
		datos = unosDatos;
		hijoIzq = null;
		hijoDer = null;
	}

	@SuppressWarnings("rawtypes")
	@Override
	public Comparable getEtiqueta() {
		return this.etiqueta;
	}

	@Override
	public IElementoAB getHijoIzq() {
		return this.hijoIzq;
	}

	@Override
	public IElementoAB getHijoDer() {
		return this.hijoDer;
	}

	@Override
	public Object getDatos() {
		return this.datos;
	}

	@Override
	public void setHijoIzq(IElementoAB elemento) {
		this.hijoIzq = (TElementoAB) elemento;
	}

	@Override
	public void setHijoDer(IElementoAB elemento) {
		this.hijoDer = (TElementoAB) elemento;
	}

	@SuppressWarnings("unchecked")
	@Override
	public boolean insertar(IElementoAB elemento) {
		if (elemento.getEtiqueta().compareTo(etiqueta) < 0) {
			if (hijoIzq != null) {
				return hijoIzq.insertar(elemento);
			} else {
				setHijoIzq(elemento);
				return true;
			}
		} else {
			if (elemento.getEtiqueta().compareTo(etiqueta) > 0) {
				if (hijoDer != null) {
					return hijoDer.insertar(elemento);
				} else {
					setHijoDer(elemento);
					return true;
				}
			} else {
				return false;
			}
		}
	}

	@Override
	public String inOrden() {
		String str = "";
		if (hijoIzq != null) {
			str = str + hijoIzq.inOrden();
		}
		str = str + etiqueta + SEPARADOR_ELEMENTOS_IMPRESOS;
		if (hijoDer != null) {
			str = str + hijoDer.inOrden();
		}
		return str;
	}

	@Override
	public String preOrden() {
		String str = etiqueta + SEPARADOR_ELEMENTOS_IMPRESOS;
		if (hijoIzq != null) {
			str = str + hijoIzq.preOrden();
		}
		if (hijoDer != null) {
			str = str + hijoDer.preOrden();
		}
		return str;
	}

	@Override
	public String postOrden() {
		String str = "";
		if (hijoIzq != null) {
			str = str + hijoIzq.postOrden();
		}
		if (hijoDer != null) {
			str = str + hijoDer.postOrden();
		}
		str = str + etiqueta + SEPARADOR_ELEMENTOS_IMPRESOS;
		return str;
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Override
	public IElementoAB buscar(Comparable unaEtiqueta) {
		if (unaEtiqueta.compareTo(etiqueta) == 0) {
			return this;
		} else {
			if (unaEtiqueta.compareTo(etiqueta) < 0) {
				if (hijoIzq != null) {
					return hijoIzq.buscar(unaEtiqueta);
				} else {
					return null;
				}
			} else {
				if (hijoDer != null) {
					return hijoDer.buscar(unaEtiqueta);
				} else {
					return null;
				}
			}
		}
	}

	@Override
	public int obtenerAltura() {
		int a = 0;
		int b = 0;
		if (hijoIzq != null) {
			a = hijoIzq.obtenerAltura();
			a = a + 1;
		}
		if (hijoDer != null) {
			b = hijoDer.obtenerAltura();
			b = b + 1;
		}
		if (a >= b) {
			return a;
		} else {
			return b;
		}
	}

	public IElementoAB eliminar(Comparable unaEtiqueta) {

		IElementoAB nodoADevolver = this;

		if (unaEtiqueta.compareTo(this.etiqueta) < 0) {
			if (hijoIzq != null) {
				hijoIzq = hijoIzq.eliminar(unaEtiqueta);
			} else {
				return null;
			}
		} else {
			if (unaEtiqueta.compareTo(this.etiqueta) > 0) {
				if (hijoDer != null) {
					hijoDer = hijoDer.eliminar(unaEtiqueta);
				} else {
					return null;
				}
			} else {
				if (this.esHoja()) {
					nodoADevolver = null;
				} else {
					if (hijoIzq == null) {
						nodoADevolver = hijoDer;
					} else {
						if (hijoDer == null) {
							nodoADevolver = hijoIzq;
						} else {
							nodoADevolver = this.nuevaRaizSubArbol();
						}
					}
				}
			}
		}
		return nodoADevolver;

	}

	public IElementoAB nuevaRaizSubArbol() {
		IElementoAB elInmediatoAnterior = this.hijoIzq;
		while (elInmediatoAnterior.getHijoDer() != null) {
			elInmediatoAnterior = elInmediatoAnterior.getHijoDer();
		}
		eliminar(elInmediatoAnterior.getEtiqueta());
		elInmediatoAnterior.setHijoIzq(hijoIzq);
		elInmediatoAnterior.setHijoDer(hijoDer);
		return elInmediatoAnterior;
	}

	public boolean esHoja() {
		if (hijoDer == null && hijoIzq == null) {
			return true;
		} else {
			return false;
		}
	}

	public int obtenerTamano() {
		int contador = 1;
		if (hijoIzq != null) {
			contador = contador + hijoIzq.obtenerTamano();
		}
		if (hijoDer != null) {
			contador = contador + hijoDer.obtenerTamano();
		}
		return contador;
	}

	@Override
	public int obtenerNodosNivel(int nivelActual, int nivelBuscado) {
		int contador = 0;
		int nivel = nivelActual + 1;
		if (nivel != nivelBuscado) {
			if (hijoIzq != null) {
				contador = contador
						+ hijoIzq.obtenerNodosNivel(nivel, nivelBuscado);
			}
			if (hijoDer != null) {
				contador = contador
						+ hijoDer.obtenerNodosNivel(nivel, nivelBuscado);
			}
		}
		if (nivel == nivelBuscado) {
			if (hijoIzq != null) {
				contador = contador + 1;
			}
			if (hijoDer != null) {
				contador = contador + 1;
			}
		}
		return contador;
	}

	@Override
	public boolean esArbolBinario() {
		boolean izq = true;
		boolean der = true;
		if (hijoIzq != null) {
			if (this.getEtiqueta().compareTo(hijoIzq.getEtiqueta()) > 0) {
				izq = hijoIzq.esArbolBinario();
			} else {
				return false;
			}
		}
		if (hijoDer != null) {
			if (this.getEtiqueta().compareTo(hijoDer.getEtiqueta()) < 0) {
				der = hijoDer.esArbolBinario();
			} else {
				return false;
			}
		}
		return (izq && der);
	}

	@Override
	public String hojasMayorMenor() {
		String str = "";
		if (hijoDer != null) {

			str = str + hijoDer.hojasMayorMenor();

		}
		if (esHoja()) {
			str = str + etiqueta + SEPARADOR_ELEMENTOS_IMPRESOS;
		}
		if (hijoIzq != null) {

			str = str + hijoIzq.hojasMayorMenor();

		}
		return str;
	}

}
